<?php

namespace plugin\ycMassage\app\api\controller;

use app\common\manager\SettingsMgr;
use app\common\service\UploadService;
use plugin\ycMassage\app\BaseController;
use plugin\ycMassage\app\model\MassageAppointmentService;
use plugin\ycMassage\app\model\MassageCoupon;
use plugin\ycMassage\app\model\MassageCouponCode;
use plugin\ycMassage\app\model\MassageMoneyRegister;
use plugin\ycMassage\app\model\MassageOrders;
use plugin\ycMassage\app\model\MassageOrdersAddress;
use plugin\ycMassage\app\model\MassageOrdersRefund;
use plugin\ycMassage\app\model\MassageOrdersSub;
use plugin\ycMassage\app\model\MassageOrdersTransferring;
use plugin\ycMassage\app\model\MassageOrdersTravel;
use plugin\ycMassage\app\model\MassageTravel;
use plugin\ycMassage\app\model\MassageUser;
use plugin\ycMassage\app\model\MassageUserAddress;
use plugin\ycMassage\app\model\MassageUserBill;
use plugin\ycMassage\app\model\MassageUserChannels;
use plugin\ycMassage\app\model\MassageUserFreezeMoney;
use plugin\ycMassage\app\model\MassageUserSalesman;
use plugin\ycMassage\app\model\MassageUserTechnician;
use plugin\ycMassage\app\model\MassageUserTechnicianScheduling;
use plugin\ycMassage\app\model\MassageUserTechnicianService;
use plugin\ycMassage\app\model\MassageUserWechat;
use plugin\ycMassage\utils\enum\ActionIdentity;
use plugin\ycMassage\utils\enum\CouponCodeState;
use plugin\ycMassage\utils\enum\Examine;
use plugin\ycMassage\utils\enum\NoticeType;
use plugin\ycMassage\utils\enum\OrdersState;
use plugin\ycMassage\utils\enum\OrdersType;
use plugin\ycMassage\utils\enum\PayType;
use plugin\ycMassage\utils\enum\ServiceState;
use plugin\ycMassage\utils\enum\State;
use support\Request;
use WePay\Order as WeChatPay;
use plugin\ycMassage\utils\Epay;
use plugin\ycMassage\utils\notice\Notice;
use plugin\ycMassage\utils\ServicePriceBuilder;
use plugin\ycMassage\utils\Str;
use think\facade\Db;
use think\facade\Env;

class OrdersController extends BaseController {
    public function create(Request $request) {
        $type = $request->post('type');
        $order = null;
        try {
            switch ($type) {
                case OrdersType::RESERVATION['value']:
                    $order = $this->createReservation($request);
                    break;
                case OrdersType::OVERTIME['value']:
                    $order = $this->createOvertime($request);
                    break;
                case OrdersType::MONEY['value']:
                    $order = $this->createMoney($request);
                    break;
                case OrdersType::DEALER_APPLY['value']:
                    $order = $this->createDealerApply($request);
                    break;
                default:
                    throw new \Exception('未知订单类型');
            }
            return $this->createPay($request, $order);
        } catch (\Throwable $th) {
            if ($order) {
                return $this->json($th->getMessage(), 404, $order);
            }
            return $this->fail($th->getMessage());
        }
    }
    public function payByOrders(Request $request) {
        $uid = $request->uid;
        $saas_appid = $request->saas_appid;
        $trade = $request->post('trade');
        $order = null;
        try {
            $order = MassageOrders::where(['saas_appid' => $saas_appid, 'uid' => $uid, 'trade' => $trade, 'state' => OrdersState::NOT_PAY['value']])->find();
            if (!$order) {
                return $this->fail('订单不存在');
            }
            return $this->createPay($request, $order);
        } catch (\Throwable $th) {
            if ($order) {
                return $this->json($th->getMessage(), 404, $order);
            }
            return $this->fail($th->getMessage());
        }
    }
    public function createPay(Request $request, $order) {
        $platform = $request->post('platform');
        switch ($request->post('pay_type')) {
            case PayType::WXPAY['value']:
                switch ($platform) {
                    case 'H5':
                        if ($request->isWehcatBrowser) {
                            return $this->successRes($this->wxPay($order));
                        } else {
                            return $this->successRes($this->wxH5Pay($order));
                        }
                    case 'MP-WEIXIN':
                        return $this->successRes($this->wxMiniPay($order, $request));
                    case 'APP':
                        return $this->successRes($this->wxAppPay($order, $request));
                }
            case PayType::ALIPAY['value']:
                return $this->successRes($this->aliPay($order));
            case PayType::EPAY['value']:
                return $this->successRes($this->ePay($order));
            case PayType::MONEY['value']:
                return $this->moneyPay($order);
        }
        throw new \Exception('未知支付方式');
    }
    public function createReservation(Request $request) {
        $saas_appid = $request->saas_appid;
        $D = $request->post();
        # 用户信息
        $MassageUser = MassageUser::where(['saas_appid' => $request->saas_appid, 'id' => $request->uid])->find();
        if (!$MassageUser) {
            throw new \Exception('用户不存在', 1001);
        }
        $user_config = getHpConfig('', $saas_appid, 'user');
        if (isset($user_config['force_realname']) && $user_config['force_realname'] && !$MassageUser->realname) {
            throw new \Exception('请先实名认证', 1001);
        }
        # 技师信息
        $MassageUserTechnician = MassageUserTechnician::where(['saas_appid' => $request->saas_appid, 'uid' => $D['technician_id'], 'examine' => Examine::YES['value']])->find();
        if (!$MassageUserTechnician) {
            throw new \Exception(MassageReplaceIndustryPersonnelName($saas_appid, '技师不存在'), 1002);
        }
        if ($MassageUserTechnician->uid === $MassageUser->id && Env::get('APP_MODE') != 'dev') {
            throw new \Exception('不能预约自己', 1002);
        }

        $individual_settlement = getHpConfig('individual_settlement', $saas_appid, 'technician');
        if (!$individual_settlement && (!$MassageUserTechnician->work_mch_id || !$MassageUserTechnician->work_shop_id)) {
            throw new \Exception(MassageReplaceIndustryPersonnelName($saas_appid, '个人技师暂停接单'), 1002);
        }
        if ($MassageUserTechnician->resting) {
            throw new \Exception(MassageReplaceIndustryPersonnelName($saas_appid, '技师休息中'), 1002);
        }
        # 技师排班信息
        $MassageUserTechnicianScheduling = MassageUserTechnicianScheduling::where(['saas_appid' => $request->saas_appid, 'id' => $D['scheduling_id']])->find();
        if (!$MassageUserTechnicianScheduling) {
            throw new \Exception('排班不存在', 1003);
        }
        # 用户地址信息
        $to_shop = State::NO['value'];
        $travel_price = 0;
        $commuting = 0;
        if (isset($D['to_shop']) && $D['to_shop']) {
            $to_shop = State::YES['value'];
        }
        $MassageUserAddress = null;
        $service_time = $D['servive_time'];
        if (!$to_shop) {
            $MassageUserAddress = MassageUserAddress::where(['saas_appid' => $request->saas_appid, 'uid' => $MassageUser->id, 'id' => $D['address_id']])
                ->withoutField('id,uid,is_default,update_time,create_time')->find();
            if (!$MassageUserAddress) {
                throw new \Exception('地址不存在', 1004);
            }
            # 计算出行时间和费用 ----------------------------------------------------------------------------------------
            $now = date('H:i:s', strtotime($service_time));
            $travel = $D['travel'];
            if ($travel['type'] === 'custom') {
                $MassageTravel = MassageTravel::where(['id' => $travel['id']])->find();
                if ($MassageTravel->start_time && $MassageTravel->end_time) {
                    if ($now < $MassageTravel->start_time || $now > $MassageTravel->end_time) {
                        throw new \Exception($MassageTravel->title . '出行方式不在服务时间范围内', 1005);
                    }
                }
                $MassageTravelData = [
                    'type' => 'custom',
                    'id' => $MassageTravel->id,
                    'name' => $MassageTravel->title,
                    'start_distance' => $MassageTravel->start_distance,
                    'start_price' => $MassageTravel->start_price,
                    'mileage_price' => $MassageTravel->mileage_price,
                    'virtually_mileage' => $MassageTravel->virtually_mileage,
                    'commuting' => $MassageTravel->commuting
                ];
            } else {
                $config = getHpConfig('', $saas_appid, 'travel');
                if ($travel['type'] === 'taxi') {
                    if (isset($config['taxi_state']) && $config['taxi_state']) {
                        $MassageTravelData = [
                            'type' => 'taxi',
                            'name' => '出租车',
                            'start_distance' => $config['taxi_start_distance'],
                            'start_price' => $config['taxi_start_price'],
                            'mileage_price' => $config['taxi_mileage_price'],
                            'virtually_mileage' => $config['taxi_virtually_mileage'],
                            'commuting' => $config['taxi_commuting']
                        ];
                    } else {
                        throw new \Exception('出租车服务未开启', 1006);
                    }
                } else {
                    if (isset($config['bus_state']) && $config['bus_state']) {
                        if (!empty($config['bus_time'])) {
                            list($start_time, $end_time) = $config['bus_time'];
                            if ($now < $start_time || $now > $end_time) {
                                throw new \Exception('公交服务不在运营时间范围内', 1007);
                            }
                        }
                        $MassageTravelData = [
                            'type' => 'bus',
                            'name' => '公交',
                            'start_distance' => 0,
                            'start_price' => $config['bus_price'],
                            'mileage_price' => 0,
                            'virtually_mileage' => 0,
                            'commuting' => $config['bus_commuting']
                        ];
                    } else {
                        throw new \Exception('公交服务未开启', 1006);
                    }
                }
            }
            if (empty($MassageTravelData)) {
                throw new \Exception('无可用的出行方式', 1008);
            }
            # 出行费用
            $travel_price = $MassageTravelData['start_price'];
            # 起步距离
            $start_distance = $MassageTravelData['start_distance'] * 1000;
            # 用户地址坐标和技师坐标距离
            $distance = MassageHaversineDistance($MassageUserAddress->latitude, $MassageUserAddress->longitude, $MassageUserTechnician->latitude, $MassageUserTechnician->longitude);
            $distance = $distance * 1000 + $distance * 1000 * ($MassageTravelData['virtually_mileage'] / 100);
            # 超出里程
            $mileage = 0;
            # 超出里程费用
            $mileage_price = 0;
            # 判断是否超出起步距离
            if ($start_distance > 0 && $distance >= $start_distance) {
                $mileage = $distance - $start_distance;
            }
            # 计算超出里程费用
            if ($mileage > 0 && $MassageTravelData['mileage_price'] > 0) {
                $mileage = ceil($mileage / 1000);
                $mileage_price = round($mileage * $MassageTravelData['mileage_price'], 2);
                $travel_price += $mileage_price;
            }
            # 来回出行费用
            $travel_price = $travel_price * 2;
            # 出行耗时
            $commuting = $MassageTravelData['commuting'] * ceil($distance / 1000);
            # 计算出行时间和费用 ----------------------------------------------------------------------------------------
        }

        # 服务 -----------------------------------------------------------------------------------------------------
        $serviceIds = [];
        $serviceNums = [];
        foreach ($D['service'] as $key => $item) {
            $serviceIds[] = $item['id'];
            $serviceNums[$item['id']] = abs((int)$item['num']);
        }
        $field = [
            'uts.price as uts_price,uts.service_id',
            's.title,s.price,s.overtime_price,s.overtime_duration,s.price,s.service_duration,s.overtime_separate,s.material_price',
        ];
        # 获取所预约的服务
        $MassageUserTechnicianService = MassageUserTechnicianService::alias('uts')
            ->where(['uts.saas_appid' => $request->saas_appid, 'uts.uid' => $MassageUserTechnician->uid, 'uts.state' => State::YES['value']])
            ->whereIn('uts.service_id', $serviceIds)
            ->join('massage_service s', 's.id = uts.service_id AND s.examine = ' . Examine::YES['value'])
            ->field($field)
            ->select()
            ->each(function ($item) use ($serviceNums) {
                $item->num = $serviceNums[$item->service_id];
                # 判断技师是否定价
                if ($item->uts_price > 0) {
                    $item->price = $item->uts_price;
                }
            });
        if ($MassageUserTechnicianService->isEmpty()) {
            throw new \Exception('服务不存在', 1004);
        }
        # price:服务总价
        # service_duration:服务总时长
        # basic_price:基础服务单价
        # basic_duration:基础服务时长
        # overtime_price:加钟服务单价
        # overtime_duration:加钟服务时长
        # material_price:材料费
        # order:子订单
        $ServicePriceBuilder = new ServicePriceBuilder($MassageUserTechnicianService);
        $hasReservationState = MassageAppointmentService::hasReservation(
            $MassageUserTechnicianScheduling->id,
            $MassageUserTechnicianScheduling->start_time,
            $MassageUserTechnicianScheduling->end_time,
            $service_time,
            $ServicePriceBuilder->service_duration + $commuting
        );
        if (!$hasReservationState) {
            throw new \Exception('服务时间已被预约，请刷新查看', 1005);
        }
        # 服务 -----------------------------------------------------------------------------------------------------

        # 优惠券 ---------------------------------------------------------------------------------------------------
        $CouponCode = null;
        if (!empty($D['coupon'])) {
            $couponWhere = [
                ['uc.uid', '=', $MassageUser->id],
                ['uc.state', '=', CouponCodeState::YES['value']],
                ['uc.code', 'in', $D['coupon']]
            ];
            $CouponCode = MassageCouponCode::alias('uc')->where($couponWhere)
                ->join('massage_coupon c', 'c.id=uc.coupon_id')
                ->field('uc.id,c.money,c.use_type,c.full_money')
                ->select();
            if (!$CouponCode->isEmpty()) {
                $ServicePriceBuilder->useCoupon($CouponCode);
            } else {
                $CouponCode = null;
            }
        }
        # 优惠券 ---------------------------------------------------------------------------------------------------
        $num = $ServicePriceBuilder->num;
        $origin_price = $ServicePriceBuilder->origin_price + $travel_price;
        $price = $ServicePriceBuilder->price + $travel_price;
        Db::startTrans();
        try {
            $MassageOrders = new MassageOrders();
            $MassageOrders->saas_appid = $request->saas_appid;
            $MassageOrders->uid = $MassageUser->id;
            $MassageOrders->alias_id = $MassageUserTechnician->uid;
            $MassageOrders->mch_id = $MassageUserTechnician->work_mch_id;
            $MassageOrders->shop_id = $MassageUserTechnician->work_shop_id;
            $MassageOrders->origin_price = $origin_price;
            $MassageOrders->price = $price;
            $MassageOrders->basic_price = $ServicePriceBuilder->basic_price;
            $MassageOrders->overtime_price = $ServicePriceBuilder->overtime_price;
            $MassageOrders->material_price = $ServicePriceBuilder->material_price;
            $MassageOrders->travel_price = $travel_price;
            $MassageOrders->coupon_money = $ServicePriceBuilder->coupon_money;
            $MassageOrders->coupon_average_money = $ServicePriceBuilder->coupon_average_money;
            $MassageOrders->num = $num;
            if ($MassageUser->puid) {
                $MassageOrders->puid = $MassageUser->puid;
            }
            if ($ServicePriceBuilder->basic_num > 1) {
                # 最多展示两项
                $MassageOrders->title = "预约{$ServicePriceBuilder->title[0]}+{$ServicePriceBuilder->title[1]}等一共{$ServicePriceBuilder->num}项服务";
            } else {
                $MassageOrders->title = "预约{$ServicePriceBuilder->title[0]}*{$ServicePriceBuilder->basic_num}";
            }
            $trade = date('YmdHis') . Str::random(6, 1);
            $tradeCreateNum = 0;
            while (MassageOrders::where('trade', $trade)->count() > 0) {
                $trade = date('YmdHis') . Str::random(6, 1);
                $tradeCreateNum++;
                if ($tradeCreateNum > 10) {
                    throw new \Exception('生成订单失败', 1006);
                }
            }
            $MassageOrders->trade = $trade;
            $MassageOrders->orders_type = OrdersType::RESERVATION['value'];
            $MassageOrders->expire_time = date('Y-m-d H:i:s', time() + 600);
            $MassageOrders->coupons = $ServicePriceBuilder->coupon;
            $MassageOrders->remark = $D['remark'];
            if ($request->channels_id) {
                $MassageOrders->channels_id = $request->channels_id;
            }
            $MassageOrders->to_shop = $to_shop;
            $MassageOrders->save();
            $start_time = $service_time;
            # 子订单
            foreach ($ServicePriceBuilder->order as $key => $item) {
                $item['orders_id'] = $MassageOrders->id;
                $item['saas_appid'] = $request->saas_appid;
                $item['uid'] = $MassageUser->id;
                $item['technician_id'] = $MassageUserTechnician->uid;
                if ($request->channels_id) {
                    $item['channels_id'] = $request->channels_id;
                }
                ksort($item);
                $MassageOrdersSub = new MassageOrdersSub();
                $MassageOrdersSub->save($item);
                # 每项服务
                $MassageAppointmentService = new MassageAppointmentService;
                $MassageAppointmentService->saas_appid = $request->saas_appid;
                $MassageAppointmentService->uid = $MassageUser->id;
                $MassageAppointmentService->technician_id = $MassageUserTechnician->uid;
                $MassageAppointmentService->scheduling_id = $MassageUserTechnicianScheduling->id;
                $MassageAppointmentService->mch_id = $MassageUserTechnician->work_mch_id;
                $MassageAppointmentService->shop_id = $MassageUserTechnician->work_shop_id;
                $MassageAppointmentService->orders_id = $MassageOrders->id;
                $MassageAppointmentService->orders_sub_id = $MassageOrdersSub->id;
                $MassageAppointmentService->service_id = $item['service_id'];
                $MassageAppointmentService->start_time = $start_time;
                $MassageAppointmentService->duration = $item['duration'];
                if ($key === 0) {
                    $MassageAppointmentService->commuting_duration = $commuting;
                }
                $MassageAppointmentService->to_shop = $to_shop;
                $MassageAppointmentService->save();
                $start_time = date('Y-m-d H:i:s', strtotime($start_time . "+{$item['duration']} minutes"));
            }
            # 优惠券
            if (!empty($ServicePriceBuilder->coupon)) {
                $useMassageCouponCode = MassageCouponCode::whereIn('id', $ServicePriceBuilder->coupon)->select();
                foreach ($useMassageCouponCode as $item) {
                    $item->state = CouponCodeState::NO['value'];
                    $item->use_time = date('Y-m-d H:i:s');
                    $item->save();
                    $MassageCoupon = MassageCoupon::where(['id' => $item->coupon_id])->find();
                    if ($MassageCoupon) {
                        $MassageCoupon->use_num = Db::raw('use_num+1');
                        $MassageCoupon->save();
                    }
                }
            }
            # 技师排班
            $MassageUserTechnicianScheduling->appointment_time = MassageUserTechnicianScheduling::getNextAppointmentTime($MassageUserTechnicianScheduling, $ServicePriceBuilder->service_duration);
            $MassageUserTechnicianScheduling->save();
            # 用户地址
            if (!$to_shop) {
                $MassageOrdersAddress = new MassageOrdersAddress;
                $MassageOrdersAddress->orders_id = $MassageOrders->id;
                $MassageOrdersAddress->save($MassageUserAddress->toArray());
                # 出行方式
                $MassageOrdersTravel = new MassageOrdersTravel();
                $MassageOrdersTravel->saas_appid = $MassageOrders->saas_appid;
                $MassageOrdersTravel->orders_id = $MassageOrders->id;
                $MassageOrdersTravel->travel_type = $MassageTravelData['type'];
                if (isset($MassageTravelData['id'])) {
                    $MassageOrdersTravel->alias_id = $MassageTravelData['id'];
                }
                $MassageOrdersTravel->name = $MassageTravelData['name'];
                $MassageOrdersTravel->travel_price = $travel_price;
                $MassageOrdersTravel->mileage_price = $mileage_price;
                $MassageOrdersTravel->distance = $distance;
                $MassageOrdersTravel->mileage = $mileage;
                $MassageOrdersTravel->commuting = $commuting;
                $MassageOrdersTravel->save();
            }
            Db::commit();
            return $MassageOrders;
        } catch (\Throwable $th) {
            Db::rollback();
            throw $th;
        }
    }
    public function createOvertime(Request $request) {
        $project = $request->post('project');
        $appointment_service_id = $request->post('appointment_service_id');
        Db::startTrans();
        try {
            $where = [
                ['id', '=', $appointment_service_id],
                ['saas_appid', '=', $request->saas_appid],
                ['uid', '=', $request->uid],
                ['state', '=', ServiceState::ING['value']]
            ];

            //加钟的订单服务
            $model = MassageAppointmentService::where($where)->find();

            if (!$model) {
                throw new \Exception('服务不存在或不在服务中');
            }
            // 技师正在进行的服务
            $technicianAppointmentServic = MassageAppointmentService::where(['technician_id' => $model->technician_id, 'scheduling_id' => $model->scheduling_id])->order('start_time asc')->select();
            $endTime = null;
            $start = false;
            $startTime = null;
            foreach ($technicianAppointmentServic as $item) {
                if ($start) {
                    if ($item->orders_id == $model->orders_id) {
                        $startTime += $item->duration * 60;
                    }
                    if ($item->uid != $model->uid) {
                        $endTime = strtotime($item->start_time);
                        break;
                    }
                }
                if ($item->id == $model->id) {
                    $startTime = strtotime($item->service_start_time) + $item->duration * 60;
                    $start = true;
                }
            }
            # 剩余分钟
            if (!$endTime) {
                $remaining_minutes = 9999;
            } else {
                $remaining_minutes = ceil(($endTime - $startTime) / 60);
            }


            if ($remaining_minutes <= 0) {
                throw new \Exception(MassageReplaceIndustryPersonnelName($request->saas_appid, '当前技师已经没有服务时间了'));
            }
            $origin_price = 0;
            $price = 0;
            $num = 0;
            $titles = [];
            $duration = 0;

            foreach ($project as $key => $item) {

                /*
                $where = [
                    ['apps.id', '=', $item['apps_id']],
                    ['apps.orders_id', '=', $model->orders_id],
                    ['apps.state', 'in', [
                        ServiceState::WAIT_START['value'],
                        ServiceState::TRAVELING['value'],
                        ServiceState::ARRIVAL['value'],
                        ServiceState::ING['value'],
                    ]],
                    ['s.overtime_state', '=', State::YES['value']]
                ];
                $service = MassageAppointmentService::alias('apps')->where($where)
                    ->join('massage_service s', 's.id=apps.service_id')
                    ->field('s.id,s.title,s.overtime_separate,s.overtime_price,s.price,s.overtime_duration,s.service_duration,apps.id as apps_id')
                    ->find();

                    */


                //不能从进行中的服务筛选

                $where = [
                    ['uts.saas_appid', '=', $request->saas_appid],
                    ['uts.uid', '=', $request->uid],
                    ['uts.service_id', '=', $item['apps_id']],
                    ['uts.state', '=', ServiceState::WAIT_START['value']]
                ];


                $smodel = MassageUserTechnicianService::alias('uts')->where($where);
                $service = $smodel->join('massage_service ms', 'ms.id = uts.service_id')
                    ->field('ms.*,ms.id as apps_id,uts.id as uts_id,uts.state')
                    ->find();




                if (!$service) {
                    throw new \Exception('服务不存在或不在服务中!');
                }
                $titles[] = $service->title;
                if ($service->overtime_separate) {
                    $origin_price += $service->overtime_price * $item['num'];
                    $price += $service->overtime_price * $item['num'];
                    $project[$key]['price'] = $service->overtime_price * $item['num'];
                    $project[$key]['unit_price'] = $service->overtime_price;
                    $duration += $service->overtime_duration * $item['num'];
                } else {
                    $origin_price += $service->price * $item['num'];
                    $price += $service->price * $item['num'];
                    $project[$key]['price'] = $service->price * $item['num'];
                    $project[$key]['unit_price'] = $service->price;
                    $duration += $service->service_duration * $item['num'];
                }
                $project[$key]['service_id'] = $service->id;
                $num += $item['num'];
            }




            if ($remaining_minutes < $duration) {
                throw new \Exception(MassageReplaceIndustryPersonnelName($request->saas_appid, '当前技师已经没有服务时间了'));
            }
            $MassageUser = MassageUser::where(['saas_appid' => $request->saas_appid, 'id' => $request->uid])->find();
            if (!$MassageUser) {
                throw new \Exception('用户不存在', 1001);
            }
            $MassageUserTechnician = MassageUserTechnician::where(['uid' => $model->technician_id])->find();
            if (!$MassageUserTechnician) {
                throw new \Exception(MassageReplaceIndustryPersonnelName($request->saas_appid, '技师不存在'));
            }
            $MassageOrders = new MassageOrders();
            $MassageOrders->orders_id = $model->orders_id;
            $MassageOrders->saas_appid = $model->saas_appid;
            $MassageOrders->uid = $model->uid;
            $MassageOrders->alias_id = $model->technician_id;
            $MassageOrders->mch_id = $MassageUserTechnician->work_mch_id;
            $MassageOrders->shop_id = $MassageUserTechnician->work_shop_id;
            $MassageOrders->origin_price = $origin_price;
            $MassageOrders->price = $price;
            $MassageOrders->num = $num;
            if ($MassageUser->puid) {
                $MassageOrders->puid = $MassageUser->puid;
            }
            if (count($titles) > 1) {
                # 最多展示两项
                $MassageOrders->title = "加钟{$titles[0]}+{$titles[1]}等一共{$num}项服务";
            } else {
                $MassageOrders->title = "加钟{$titles[0]}*{$num}";
            }
            $trade = date('YmdHis') . Str::random(6, 1);
            $tradeCreateNum = 0;
            while (MassageOrders::where('trade', $trade)->count() > 0) {
                $trade = date('YmdHis') . Str::random(6, 1);
                $tradeCreateNum++;
                if ($tradeCreateNum > 10) {
                    throw new \Exception('生成订单失败', 1006);
                }
            }
            $MassageOrders->trade = $trade;
            $MassageOrders->orders_type = OrdersType::OVERTIME['value'];
            $MassageOrders->expire_time = date('Y-m-d H:i:s', time() + 600);
            if ($request->channels_id) {
                $MassageOrders->channels_id = $request->channels_id;
            }
            $MassageOrders->to_shop = $model->to_shop;
            $MassageOrders->save();
            # 子订单
            foreach ($project as $item) {
                $MassageOrdersSub = new MassageOrdersSub();
                $MassageOrdersSub->orders_id = $MassageOrders->id;
                $MassageOrdersSub->saas_appid = $request->saas_appid;
                $MassageOrdersSub->uid = $MassageUser->id;
                $MassageOrdersSub->technician_id = $model->technician_id;

                //这里是加时间的关键，在支付成功后加时间,实际逻辑只能是同服务才加时间
                //不能用apps_id，因为apps_id是service_id,要用起始的服务id
                // $MassageOrdersSub->appointment_service_id = $item['apps_id'];
                $MassageOrdersSub->appointment_service_id = $appointment_service_id;

                $MassageOrdersSub->service_id = $item['service_id'];

                $MassageOrdersSub->num = $item['num'];
                $MassageOrdersSub->origin_price = $item['price'];
                $MassageOrdersSub->price = $item['price'];
                $MassageOrdersSub->unit_price = $item['unit_price'];
                if ($request->channels_id) {
                    $MassageOrdersSub->channels_id = $request->channels_id;
                }
                $MassageOrdersSub->save();
            }
            if (!$model->to_shop) {
                $OrdersAddress = MassageOrdersAddress::where(['orders_id' => $model->orders_id])->withoutField('id,uid,orders_id,update_time,create_time')->find();
                $MassageOrdersAddress = new MassageOrdersAddress();
                $MassageOrdersAddress->orders_id = $MassageOrders->id;
                $MassageOrdersAddress->save($OrdersAddress->toArray());
            }
            # 技师排班信息
            $MassageUserTechnicianScheduling = MassageUserTechnicianScheduling::where(['saas_appid' => $request->saas_appid, 'id' => $model->scheduling_id])->find();
            if (!$MassageUserTechnicianScheduling) {
                throw new \Exception('排班不存在', 1003);
            }
            # 技师排班
            $MassageUserTechnicianScheduling->appointment_time = MassageUserTechnicianScheduling::getNextAppointmentTime($MassageUserTechnicianScheduling, $duration);
            if (!$MassageUserTechnicianScheduling->appointment_time) {
                //  throw new \Exception(MassageReplaceIndustryPersonnelName($request->saas_appid, '技师排班时间不足'));
            }
            $MassageUserTechnicianScheduling->save();
            Db::commit();
            return $MassageOrders;
        } catch (\Throwable $th) {
            Db::rollback();
            throw $th;
        }
    }
    public function createMoney(Request $request) {
        $saas_appid = $request->saas_appid;
        $id = $request->post('id');
        $money = abs((float)$request->post('money'));
        # 用户信息
        $MassageUser = MassageUser::where(['saas_appid' => $request->saas_appid, 'id' => $request->uid])->find();
        if (!$MassageUser) {
            throw new \Exception('用户不存在', 1001);
        }
        $give_money = 0;
        if ($id) {
            $MassageMoneyRegister = MassageMoneyRegister::where(['id' => $id, 'saas_appid' => $saas_appid])
                ->whereRaw("(start_time IS NULL OR start_time <= NOW()) AND (end_time IS NULL OR end_time >= NOW())")
                ->find();
            if (!$MassageMoneyRegister) {
                throw new \Exception('充值套餐不存在', 1001);
            }
            $money = $MassageMoneyRegister->money;
            $give_money = $MassageMoneyRegister->give_money;
        } else {
            $money_min_register = getHpConfig('money_min_register', $saas_appid, 'money');
            if ($money < 0) {
                throw new \Exception('充值金额不能小于0', 1001);
            }
            if ($money_min_register && $money < $money_min_register) {
                throw new \Exception('充值金额不能小于' . $money_min_register, 1001);
            }
        }
        Db::startTrans();
        try {
            $MassageOrders = new MassageOrders();
            $MassageOrders->saas_appid = $request->saas_appid;
            $MassageOrders->uid = $MassageUser->id;
            $MassageOrders->alias_id = $MassageUser->id;
            $MassageOrders->origin_price = $money;
            $MassageOrders->price = $money;
            $MassageOrders->give_price = $give_money;
            if ($MassageUser->puid) {
                $MassageOrders->puid = $MassageUser->puid;
            }
            $MassageOrders->title = "预充值{$money}元";
            if ($give_money > 0) {
                $MassageOrders->title = "预充值{$money}元，赠送{$give_money}元";
            }
            $trade = date('YmdHis') . Str::random(6, 1);
            $tradeCreateNum = 0;
            while (MassageOrders::where('trade', $trade)->count() > 0) {
                $trade = date('YmdHis') . Str::random(6, 1);
                $tradeCreateNum++;
                if ($tradeCreateNum > 10) {
                    throw new \Exception('生成订单失败', 1006);
                }
            }
            $MassageOrders->trade = $trade;
            $MassageOrders->orders_type = OrdersType::MONEY['value'];
            $MassageOrders->expire_time = date('Y-m-d H:i:s', time() + 600);
            $MassageOrders->coupons = [];
            $MassageOrders->save();
            Db::commit();
            return $MassageOrders;
        } catch (\Throwable $th) {
            Db::rollback();
            throw $th;
        }
    }
    public function createDealerApply(Request $request) {
        $saas_appid = $request->saas_appid;
        # 用户信息
        $MassageUser = MassageUser::where(['saas_appid' => $request->saas_appid, 'id' => $request->uid])->find();
        if (!$MassageUser) {
            throw new \Exception('用户不存在', 1001);
        }
        $apply_price = (float) getHpConfig('apply_price', $saas_appid, 'dealer');
        Db::startTrans();
        try {
            $MassageOrders = new MassageOrders();
            $MassageOrders->saas_appid = $request->saas_appid;
            $MassageOrders->uid = $MassageUser->id;
            $MassageOrders->alias_id = $MassageUser->id;
            $MassageOrders->origin_price = $apply_price;
            $MassageOrders->price = $apply_price;
            $MassageOrders->title = "申请开通分销权限";
            $trade = date('YmdHis') . Str::random(6, 1);
            $tradeCreateNum = 0;
            while (MassageOrders::where('trade', $trade)->count() > 0) {
                $trade = date('YmdHis') . Str::random(6, 1);
                $tradeCreateNum++;
                if ($tradeCreateNum > 10) {
                    throw new \Exception('生成订单失败', 1006);
                }
            }
            $MassageOrders->trade = $trade;
            $MassageOrders->orders_type = OrdersType::DEALER_APPLY['value'];
            $MassageOrders->expire_time = date('Y-m-d H:i:s', time() + 600);
            $MassageOrders->coupons = [];
            $MassageOrders->save();
            Db::commit();
            return $MassageOrders;
        } catch (\Throwable $th) {
            Db::rollback();
            throw $th;
        }
    }
    public static function wxPay($model) {
        $wxappid = getHpConfig('appid', $model->saas_appid, 'wx');
        if (!$wxappid) {
            throw new \Exception('未配置微信公众号');
        }
        $_config = SettingsMgr::getChildren((int)$model->saas_appid, 'pay');
        if (empty($_config['wxpay_state'])) {
            throw new \Exception("未开启微信支付");
        }
        if (empty($_config['wxpay_mch_id']) || empty($_config['wxpay_mch_key'])) {
            throw new \Exception("未配置微信支付");
        }

        $MassageUserWechat = MassageUserWechat::where(['uid' => $model->uid])->find();
        if (!$MassageUserWechat) {
            throw new \Exception('请先微信登录或在个人中心绑定微信');
        }
        if (!$MassageUserWechat->openid) {
            throw new \Exception('未绑定微信,请先绑定微信');
        }
        $config = [
            // 缓存目录配置（可选，需拥有读写权限）
            'cache_path'     => runtime_path('wxpay'),
        ];
        $config = array_merge($config, [
            'appid' => $wxappid,
            'mch_id' => $_config['wxpay_mch_id'],
            'mch_key' => $_config['wxpay_mch_key'],
        ]);

        // 创建接口实例
        $wechat = new WeChatPay($config);
        $domain = getHpConfig('domain', (int)$model->saas_appid, 'plugins_domains');
        try {
            // 组装参数，可以参考官方商户文档
            $options = [
                'body'             => $model->title,
                'out_trade_no'     => $model->trade,
                'total_fee'        => Env::get('APP_MODE') == 'dev' ? 1 : $model->price * 10 * 10,
                'trade_type'       => 'JSAPI',
                'attach'           => $model->saas_appid,
                'notify_url'       => $domain . '/app/ycMassage/Notify/wechat',
                'openid'           => $MassageUserWechat->openid,
            ];
            // 尝试创建订单
            $result = $wechat->create($options);
            if ($result['return_code'] !== 'SUCCESS') {
                throw new \Exception($result['return_msg']);
            }
            if ($result['result_code'] !== 'SUCCESS') {
                throw new \Exception($result['err_code'] . ':' . $result['err_code_des']);
            }
            $data = [
                'appId' => $wxappid,
                'timeStamp' => time() . '',
                'nonceStr' => Str::random(32),
                'package' => 'prepay_id=' . $result['prepay_id'],
                'signType' => 'MD5',
            ];
            $data['paySign'] = $wechat->getPaySign($data);
            return ['pay' => $data, 'pay_type' => 'wxpay', 'order' => ['trade' => $model->trade, 'title' => $model->title, 'price' => $model->price, 'expire_time' => $model->expire_time]];
        } catch (\Throwable $th) {
            throw new \Exception($th->getMessage());
        }
    }
    public static function wxH5Pay($model) {
        $wxappid = getHpConfig('appid', $model->saas_appid, 'wx');
        if (!$wxappid) {
            throw new \Exception('未配置微信公众号');
        }
        $_config = SettingsMgr::getChildren((int)$model->saas_appid, 'pay');
        if (empty($_config['wxpay_state'])) {
            throw new \Exception("未开启微信支付");
        }
        if (empty($_config['wxpay_mch_id']) || empty($_config['wxpay_mch_key'])) {
            throw new \Exception("未配置微信支付");
        }
        $config = [
            // 缓存目录配置（可选，需拥有读写权限）
            'cache_path'     => runtime_path('wxpay'),
        ];
        $config = array_merge($config, [
            'appid' => $wxappid,
            'mch_id' => $_config['wxpay_mch_id'],
            'mch_key' => $_config['wxpay_mch_key'],
        ]);

        // 创建接口实例
        $wechat = new WeChatPay($config);
        $domain = getHpConfig('domain', (int)$model->saas_appid, 'plugins_domains');
        try {
            // 组装参数，可以参考官方商户文档
            $options = [
                'body'             => $model->title,
                'out_trade_no'     => $model->trade,
                'total_fee'        => Env::get('APP_MODE') == 'dev' ? 1 : $model->price  * 10 * 10,
                'trade_type'       => 'WAP',
                'attach'           => $model->saas_appid,
                'notify_url'       => $domain . '/app/ycMassage/Notify/wechat',
                'spbill_create_ip' => request()->ip()
            ];
            // 尝试创建订单
            $result = $wechat->create($options);
            if ($result['return_code'] !== 'SUCCESS') {
                throw new \Exception($result['return_msg']);
            }
            if ($result['result_code'] !== 'SUCCESS') {
                throw new \Exception($result['err_code'] . ':' . $result['err_code_des']);
            }
            $data = [
                'appId' => $wxappid,
                'timeStamp' => time() . '',
                'nonceStr' => Str::random(32),
                'package' => 'prepay_id=' . $result['prepay_id'],
                'signType' => 'MD5',
            ];
            $data['paySign'] = $wechat->getPaySign($data);
            return ['pay' => $data, 'pay_type' => 'wxpay', 'order' => ['trade' => $model->trade, 'title' => $model->title, 'price' => $model->price, 'expire_time' => $model->expire_time]];
        } catch (\Throwable $th) {
            throw new \Exception($th->getMessage());
        }
    }
    public function wxMiniPay($model, $request) {
        $applet = SettingsMgr::group($model->saas_appid, 'applet');
        if (empty($applet['applet_appid']) || empty($applet['applet_secret'])) {
            throw new \Exception("请先配置小程序");
        }
        $_config = SettingsMgr::getChildren((int)$model->saas_appid, 'pay');
        if (empty($_config['wxpay_state'])) {
            throw new \Exception("未开启微信支付");
        }
        if (empty($_config['wxpay_mch_id']) || empty($_config['wxpay_mch_key'])) {
            throw new \Exception("未配置微信支付");
        }
        $code = $request->post('code');
        if (!$code) {
            throw new \Exception("微信授权Code为空");
        }
        $url = 'https://api.weixin.qq.com/sns/jscode2session';
        $Client = new \GuzzleHttp\Client();
        $response = $Client->request('GET', $url, [
            'query' => [
                'appid' => $applet['applet_appid'],
                'secret' => $applet['applet_secret'],
                'js_code' => $code,
                'grant_type' => 'authorization_code',
            ]
        ]);
        $body = $response->getBody();
        $data = json_decode($body);
        if (isset($data->errcode)) {
            throw new \Exception("[{$data->errcode}]" . $data->errmsg);
        }
        $config = [
            // 缓存目录配置（可选，需拥有读写权限）
            'cache_path'     => runtime_path('wxpay'),
        ];
        $config = array_merge($config, [
            'appid' => $applet['applet_appid'],
            'mch_id' => $_config['wxpay_mch_id'],
            'mch_key' => $_config['wxpay_mch_key'],
        ]);

        // 创建接口实例
        $wechat = new WeChatPay($config);
        $domain = getHpConfig('domain', (int)$model->saas_appid, 'plugins_domains');
        try {
            // 组装参数，可以参考官方商户文档
            $options = [
                'body'             => $model->title,
                'out_trade_no'     => $model->trade,
                'total_fee'        => Env::get('APP_MODE') == 'dev' ? 1 : $model->price  * 10 * 10,
                'trade_type'       => 'JSAPI',
                'attach'           => $model->saas_appid,
                'notify_url'       => $domain . '/app/ycMassage/Notify/wechat',
                'openid'           => $data->openid,
            ];
            // 尝试创建订单
            $result = $wechat->create($options);
            if ($result['return_code'] !== 'SUCCESS') {
                throw new \Exception($result['return_msg']);
            }
            if ($result['result_code'] !== 'SUCCESS') {
                throw new \Exception($result['err_code'] . ':' . $result['err_code_des']);
            }
            $data = [
                'appId' => $config['appid'],
                'timeStamp' => time() . '',
                'nonceStr' => Str::random(32),
                'package' => 'prepay_id=' . $result['prepay_id'],
                'signType' => 'MD5',
            ];
            $data['paySign'] = $wechat->getPaySign($data);
            return ['pay' => $data, 'pay_type' => 'wxpay', 'orderInfo' => $result, 'order' => ['trade' => $model->trade, 'title' => $model->title, 'price' => $model->price, 'expire_time' => $model->expire_time]];
        } catch (\Throwable $th) {
            throw new \Exception($th->getMessage());
        }
    }
    public function wxAppPay($model, $request) {
        $wxappid = getHpConfig('appid', $model->saas_appid, 'wechat_app');
        if (!$wxappid) {
            throw new \Exception('未配置微信开放平台');
        }
        $_config = SettingsMgr::getChildren((int)$model->saas_appid, 'pay');
        if (empty($_config['wxpay_state'])) {
            throw new \Exception("未开启微信支付");
        }
        if (empty($_config['wxpay_mch_id']) || empty($_config['wxpay_mch_key'])) {
            throw new \Exception("未配置微信支付");
        }
        $config = [
            // 缓存目录配置（可选，需拥有读写权限）
            'cache_path'     => runtime_path('wxpay'),
        ];
        $config = array_merge($config, [
            'appid' => $wxappid,
            'mch_id' => $_config['wxpay_mch_id'],
            'mch_key' => $_config['wxpay_mch_key'],
        ]);

        // 创建接口实例
        $wechat = new WeChatPay($config);
        $domain = getHpConfig('domain', (int)$model->saas_appid, 'plugins_domains');
        try {
            // 组装参数，可以参考官方商户文档
            $options = [
                'body'             => $model->title,
                'out_trade_no'     => $model->trade,
                'total_fee'        => Env::get('APP_MODE') == 'dev' ? 1 : $model->price  * 10 * 10,
                'trade_type'       => 'NATIVE',
                'attach'           => $model->saas_appid,
                'notify_url'       => $domain . '/app/ycMassage/Notify/wechat'
            ];
            // 尝试创建订单
            $result = $wechat->create($options);
            if ($result['return_code'] !== 'SUCCESS') {
                throw new \Exception($result['return_msg']);
            }
            if ($result['result_code'] !== 'SUCCESS') {
                throw new \Exception($result['err_code'] . ':' . $result['err_code_des']);
            }
            $data = [
                'appid' => $config['appid'],
                'noncestr' => Str::random(32),
                'package' => 'Sign=WXPay',
                'partnerid' => $config['mch_id'],
                'prepayid' => $result['prepay_id'],
                'timestamp' => time()
            ];
            $data['sign'] = $wechat->getPaySign($data);
            return ['pay' => $data, 'pay_type' => 'wxpay', 'orderInfo' => $result, 'order' => ['trade' => $model->trade, 'title' => $model->title, 'price' => $model->price, 'expire_time' => $model->expire_time]];
        } catch (\Throwable $th) {
            throw new \Exception($th->getMessage());
        }
    }
    public function aliPay($model) {
        return [];
    }
    public function ePay($model) {
        $_config = SettingsMgr::getChildren((int)$model->saas_appid, 'pay');
        if (empty($_config['epay_state'])) {
            throw new \Exception("未开启易支付");
        }
        if (empty($_config['epay_appid']) || empty($_config['epay_appkey']) || empty($_config['epay_url'])) {
            throw new \Exception("未配置易支付");
        }
        $domain = getHpConfig('domain', (int)$model->saas_appid, 'plugins_domains');
        $return_url = "{$domain}/app/ycMassage/#/?appid={$model->saas_appid}";
        $parameter = [
            'pid' => $_config['epay_appid'],
            "device" => "mobile",
            "type" => $_config['epay_mode'],
            "notify_url" => $domain . '/app/ycMassage/Notify/epay',
            "return_url" => $return_url,
            "out_trade_no" => $model->trade,
            "name" => $model->title,
            "money" => Env::get('APP_MODE') == 'dev' ? 0.01 : $model->price
        ];
        $payment = new Epay([
            'apiurl' => $_config['epay_url'],
            'pid' => $_config['epay_appid'],
            'key' => $_config['epay_appkey'],
        ]);
        $pay_url = $payment->getPayLink($parameter);
        return ['pay_type' => 'epay', 'pay_url' => $pay_url];
    }
    public function moneyPay($model) {
        $_config = SettingsMgr::getChildren((int)$model->saas_appid, 'pay');
        if (empty($_config['money_state'])) {
            throw new \Exception("未开启余额支付");
        }
        if (empty($_config['money_orders_type'])) {
            throw new \Exception("订单类型不允许使用余额支付");
        }
        if (!in_array($model->orders_type, $_config['money_orders_type'])) {
            throw new \Exception("订单类型不允许使用余额支付");
        }
        Db::startTrans();
        try {
            MassageUserBill::decrease("支付订单{$model->trade}", $model->uid, $model->price);
            $Find = MassageOrders::where(['id' => $model->id])->find();
            $Find->state = OrdersState::PAY['value'];
            $Find->pay_type = PayType::MONEY['value'];
            $Find->pay_time = date('Y-m-d H:i:s');
            $Find->save();
            Db::commit();
        } catch (\Throwable $th) {
            Db::rollback();
            throw $th;
        }
        try {
            MassageOrders::complete($model->trade);
        } catch (\Throwable $th) {
        }
        return $this->json('支付成功', 9000, ['order' => ['trade' => $model->trade]]);
    }
    public function list(Request $request) {
        $page = $request->get('page', 1);
        $limit = $request->get('limit', 10);
        $action = $request->get('action', 'user');
        $uid = $request->uid;
        $where = [
            ['o.saas_appid', '=', $request->saas_appid],
            ['o.orders_type', 'in', [OrdersType::RESERVATION['value'], OrdersType::OVERTIME['value']]]
        ];
        $filed = [
            'o.id,o.trade,o.remark,o.state,o.price,o.travel_price',
            'u.nickname,u.headimg',
            'ut.nickname as technician_nickname,ut.headimg as technician_headimg'
        ];
        $MassageOrdersObj = MassageOrders::alias('o');
        switch ($action) {
            case ActionIdentity::USER['value']:
                $where[] = ['o.uid', '=', $uid];
                break;
            case ActionIdentity::TECHNICIAN['value']:
                $where[] = ['o.alias_id', '=', $uid];
                break;
            case ActionIdentity::CHANNELS['value']:
                $channels_ids = MassageUserChannels::where(['uid' => $uid])->column('id');
                if (empty($channels_ids)) {
                    return $this->successRes([]);
                }
                $where[] = ['o.channels_id', 'in', $channels_ids];
                $MassageOrdersObj->join('MassageUserChannels uc', 'uc.id=o.channels_id');
                $field[] = 'uc.title as channels_title';
                break;
            default:
                return $this->fail('参数错误');
        }
        $state = $request->get('state', 'all');
        if ($state != 'all') {
            foreach (OrdersState::getData() as $key => $value) {
                if ($state == $key) {
                    $where[] = ['o.state', '=', $value['value']];
                }
            }
        }
        $MassageOrdersObj->where($where);
        $technician = $request->get('technician');
        if ($technician) {
            $where[] = ['t.name|t.mobile', 'like', "%{$technician}%"];
            $MassageOrdersObj->join('MassageUserTechnician t', 't.uid=o.alias_id');
        }
        $MassageOrdersObj->join('MassageUser u', 'u.id=o.uid');
        $MassageOrdersObj->join('MassageUser ut', 'ut.id=o.alias_id');
        $data = $MassageOrdersObj->order('o.id desc')
            ->field($filed)
            ->paginate([
                'list_rows' => $limit,
                'page' => $page
            ])->each(function ($item) {
                if (strpos($item->headimg, 'http') !== 0) {
                    $item->headimg = UploadService::url($item->headimg);
                }
                if ($item->nickname) {
                    $item->nickname = base64_decode($item->nickname);
                }
                if (strpos($item->technician_headimg, 'http') !== 0) {
                    $item->technician_headimg = UploadService::url($item->technician_headimg);
                }
                if ($item->technician_nickname) {
                    $item->technician_nickname = base64_decode($item->technician_nickname);
                }
                $item->state_text = OrdersState::getText($item->state);
                $subFiled = [
                    'os.*',
                    'uas.start_time,uas.duration',
                    's.thumb,s.title,s.overtime_separate,s.overtime_price,s.price,s.tips,s.overtime_duration,s.service_duration,s.overtime_state,s.overtime_separate,s.overtime_duration',
                    's.sales_num + s.virtually_sales_num as sales_num'
                ];
                $MassageOrdersSubObj = MassageOrdersSub::alias('os')->where(['os.orders_id' => $item->id]);
                $MassageOrdersSubObj->join('MassageService s', 's.id = os.service_id');
                $MassageOrdersSubObj->join('MassageAppointmentService uas', 'uas.orders_sub_id = os.id', 'left');
                $MassageOrdersSub = $MassageOrdersSubObj->field($subFiled)->select()
                    ->each(function ($sub) use ($item) {
                        if ($sub->thumb) {
                            $sub->thumb = UploadService::url($sub->thumb);
                        }
                        if (!$item->start_time) {
                            $item->start_time = $sub->start_time;
                        }
                    });
                $item->projects = $MassageOrdersSub->toArray();
                unset($item->id);
            });
        return $this->successRes($data);
    }
    public function getOrderState(Request $request) {
        $trade = $request->get('trade');
        $Order = MassageOrders::where(['trade' => $trade])->find();
        if ($Order && in_array($Order->state, [
            OrdersState::PAY['value'],
            OrdersState::WAIT_START['value'],
            OrdersState::FINISH['value']
        ])) {
            return $this->success('支付成功');
        }
        return $this->failFul('未支付', 11000);
    }
    public function info(Request $request) {
        $uid = $request->uid;
        $trade = $request->get('trade');
        $action = $request->get('action', 'user');
        $where = [
            ['o.trade', '=', $trade],
            ['o.saas_appid', '=', $request->saas_appid]
        ];
        switch ($action) {
            case ActionIdentity::USER['value']:
                $where[] = ['o.uid', '=', $uid];
                break;
            case ActionIdentity::TECHNICIAN['value']:
                $where[] = ['o.alias_id', '=', $uid];
                break;
            case ActionIdentity::CHANNELS['value']:
                $channels_ids = MassageUserChannels::where(['uid' => $uid])->column('id');
                if (empty($channels_ids)) {
                    return $this->fail('参数错误');
                }
                $where[] = ['o.channels_id', 'in', $channels_ids];
                break;
            default:
                return $this->fail('参数错误');
        }
        $filed = [
            'o.id,o.trade,o.remark,o.state,o.price,o.pay_time,o.pay_type,o.coupon_money,o.travel_price,o.overtime_price,o.basic_price,o.expire_time,o.channels_id,o.orders_type,o.to_shop',
            'u.nickname,u.headimg',
            'ut.nickname as technician_nickname,ut.headimg as technician_headimg',
            'address.id as address_id,address.province,address.city,address.area,address.street,address.address_detail,address.name,address.mobile',
            'ot.name as travel_name,ot.travel_price,ot.mileage_price,ot.distance,ot.mileage,ot.commuting',
            'o.shop_id,s.title as shop_title,s.logo as shop_logo,s.province as shop_province,s.city as shop_city,s.area as shop_area,s.street as shop_street,s.address as shop_address,s.longitude as shop_longitude,s.latitude as shop_latitude',
        ];
        $MassageOrdersObj = MassageOrders::alias('o')->where($where);
        $MassageOrdersObj->join('MassageOrdersAddress address', 'address.orders_id = o.id', 'LEFT');
        $MassageOrdersObj->join('MassageUser u', 'u.id=o.uid');
        $MassageOrdersObj->join('MassageUser ut', 'ut.id=o.alias_id');
        $MassageOrdersObj->join('MassageShop s', 's.id=o.shop_id', 'LEFT');
        $MassageOrdersObj->join('MassageOrdersTravel ot', 'ot.orders_id=o.id', 'left');
        $Find = $MassageOrdersObj->order('o.id desc')
            ->field($filed)
            ->find();
        if (!$Find) {
            return $this->failFul('订单不存在', 11000);
        }
        if (strpos($Find->headimg, 'http') !== 0) {
            $Find->headimg = UploadService::url($Find->headimg);
        }
        if ($Find->nickname) {
            $Find->nickname = base64_decode($Find->nickname);
        }
        if (strpos($Find->technician_headimg, 'http') !== 0) {
            $Find->technician_headimg = UploadService::url($Find->technician_headimg);
        }
        if (strpos($Find->shop_logo, 'http') !== 0) {
            $Find->shop_logo = UploadService::url($Find->shop_logo);
        }
        if ($Find->technician_nickname) {
            $Find->technician_nickname = base64_decode($Find->technician_nickname);
        }
        if ($Find->mobile) {
            $Find->mobile = substr_replace($Find->mobile, '****', 3, 4);
        }
        $Find->state_text = OrdersState::getText($Find->state);
        $MassageOrdersSubOvertimeUasIds = [];
        $subFiled = [
            'os.*',
            'uas.start_time,uas.duration,uas.state as uas_state,uas.id as appointment_service_id',
            's.thumb,s.title,s.overtime_separate,s.overtime_price,s.price as service_price,s.tips,s.overtime_duration,s.service_duration,s.overtime_state,s.overtime_separate,s.overtime_duration,s.technician_commission',
            's.sales_num + s.virtually_sales_num as sales_num'
        ];
        $MassageOrdersSubObj = MassageOrdersSub::alias('os')->where(['os.orders_id' => $Find->id]);
        $MassageOrdersSubObj->join('MassageService s', 's.id = os.service_id');
        $MassageOrdersSubObj->join('MassageAppointmentService uas', 'uas.orders_sub_id = os.id', 'left');
        $MassageOrdersSub = $MassageOrdersSubObj->field($subFiled)->select()
            ->each(function ($sub) use ($Find, &$MassageOrdersSubOvertimeUasIds) {
                if ($sub->thumb) {
                    $sub->thumb = UploadService::url($sub->thumb);
                }
                if (!$Find->start_time) {
                    $Find->start_time = $sub->start_time;
                }
                $sub->commission = round($sub->price * ($sub->technician_commission / 100), 4);
                $MassageOrdersSubOvertimeUasIds[] = $sub->appointment_service_id;
            });
        $Find->projects = $MassageOrdersSub->toArray();
        if ($Find->distance > 1000) {
            $Find->distance_text = round($Find->distance / 1000, 2) . "km";
        } else {
            $Find->distance_text = round($Find->distance) . "m";
        }
        $freeze_money = MassageUserFreezeMoney::where(['saas_appid' => $request->saas_appid, 'uid' => $uid, 'orders_id' => $Find->id,  'state' => State::NO['value']])->select();
        if (!$freeze_money->isEmpty()) {
            $Find->freeze_money = $freeze_money->toArray();
        }
        try {
            $MassageAppointmentService = MassageAppointmentService::where(['orders_id' => $Find->id])->select();
            if ($MassageAppointmentService->isEmpty()) {
                throw new \Exception('订单无服务');
            }
            foreach ($MassageAppointmentService as $item) {
                if (!in_array($item->state, [ServiceState::WAIT_START['value'], ServiceState::TRAVELING['value'], ServiceState::ARRIVAL['value']])) {
                    throw new \Exception('订单开始服务不可转单');
                }
            }
            $Find->is_transferring = true;
        } catch (\Throwable $th) {
            $Find->is_transferring = false;
        }
        if ($Find->orders_type === OrdersType::RESERVATION['value']) {
            $Find->technician_commission = 0;
            $overtimePrice = 0;
            $overtime_commission = 0;
            switch ($action) {
                case ActionIdentity::TECHNICIAN['value']:
                    if (!$Find->show_id) {
                        # 加钟订单
                        $MassageOrdersSubOvertime = MassageOrdersSub::alias('os')->whereIn('os.appointment_service_id', $MassageOrdersSubOvertimeUasIds)->where(['os.state' => OrdersState::FINISH['value']])
                            ->join('MassageService s', 's.id = os.service_id')
                            ->field(['os.price', 's.technician_commission'])
                            ->select();
                        foreach ($MassageOrdersSubOvertime as $item) {
                            $overtimePrice += $item->price;
                            $overtime_commission += round($item->price * ($item->technician_commission / 100), 4);
                        }
                        foreach ($MassageOrdersSub as $item) {
                            $Find->technician_commission += $item->commission;
                        }
                        $Find->technician_commission += $overtime_commission;
                    }
                case ActionIdentity::CHANNELS['value']:
                    if (!$Find->channels_id) {
                        break;
                    }
                    $channels = getHpConfig('', $request->saas_appid, 'channels');
                    $commission = 0;
                    $platform_commission = 0;
                    if (isset($channels['commission'])) {
                        $commission = (int)$channels['commission'];
                    }
                    if (isset($channels['platform_commission'])) {
                        $platform_commission = (int)$channels['platform_commission'];
                    }
                    $MassageUserChannels = MassageUserChannels::where(['id' => $Find->channels_id])->find();
                    if ($MassageUserChannels->commission) {
                        $commission = $MassageUserChannels->commission;
                    }
                    if ($MassageUserChannels->platform_commission) {
                        $platform_commission = $MassageUserChannels->platform_commission;
                    }
                    $Find->channels_commission = round(($Find->basic_price + $overtimePrice) * ($commission / 100), 4);
                    $platform_commission = $Find->channels_commission - round($Find->channels_commission * ($platform_commission / 100), 4);
                    if ($Find->technician_commission > 0 && $Find->channels_id) {
                        $Find->technician_commission = $Find->technician_commission - $platform_commission;
                    }
                    if ($MassageUserChannels->salesman_uid && $Find->channels_commission > 0) {
                        $salesman = getHpConfig('', $request->saas_appid, 'salesman');
                        $commission = 0;
                        if (isset($salesman['commission'])) {
                            $commission = (int)$salesman['commission'];
                        }
                        $MassageUserSalesman = MassageUserSalesman::where(['uid' => $MassageUserChannels->salesman_uid])->find();
                        if ($MassageUserSalesman->commission) {
                            $commission = $MassageUserSalesman->commission;
                        }
                        $Find->salesman_commission = round($Find->channels_commission * ($commission / 100), 4);
                        $Find->channels_commission = $Find->channels_commission - $Find->salesman_commission;
                    }
                    break;
            }
        }
        unset($Find->id);
        return $this->successRes($Find);
    }
    public function cancel(Request $request) {
        $uid = $request->uid;
        $saas_appid = $request->saas_appid;
        $trade = $request->get('trade');
        try {
            $order = MassageOrders::where(['saas_appid' => $saas_appid, 'uid' => $uid, 'trade' => $trade, 'state' => OrdersState::NOT_PAY['value']])->find();
            if (!$order) {
                throw new \Exception('订单不存在');
            }
            MassageOrders::cancel($order->trade);
            return $this->success('取消成功');
        } catch (\Throwable $th) {
            return $this->fail($th->getMessage());
        }
    }
    public function delete(Request $request) {
        $uid = $request->uid;
        $saas_appid = $request->saas_appid;
        $trade = $request->get('trade');
        Db::startTrans();
        try {
            $order = MassageOrders::where(['saas_appid' => $saas_appid, 'uid' => $uid, 'trade' => $trade, 'state' => OrdersState::CANCEL['value']])->find();
            if (!$order) {
                throw new \Exception('订单不存在或不可删除');
            }
            $ordersSub = MassageOrdersSub::where(['saas_appid' => $saas_appid, 'orders_id' => $order->id])->select();
            foreach ($ordersSub as $item) {
                $item->delete();
            }
            $order->delete();
            Db::commit();
            return $this->success('删除成功');
        } catch (\Throwable $th) {
            Db::rollback();
            return $this->fail($th->getMessage());
        }
    }
    public function refund(Request $request) {
        $uid = $request->uid;
        $saas_appid = $request->saas_appid;
        $trade = $request->post('trade');
        $use_role = $request->post('use_role', 'user');
        $refund_examine_state = getHpConfig('refund_examine_state', $saas_appid, 'orders');
        Db::startTrans();
        try {
            $where = [];
            if ($use_role == ActionIdentity::TECHNICIAN['value']) {
                $where['alias_id'] = $uid;
            } else {
                $where['uid'] = $uid;
            }
            $where['trade'] = $trade;
            $where['saas_appid'] = $saas_appid;
            $order = MassageOrders::where($where)->find();
            if (!$order) {
                throw new \Exception('订单不存在');
            }
            if (!in_array($order->state, [OrdersState::PAY['value'], OrdersState::WAIT_START['value'], OrdersState::SERVICE_ING['value']])) {
                throw new \Exception('订单不可退款');
            }
            $ordersSub = MassageOrdersSub::where(['saas_appid' => $saas_appid, 'orders_id' => $order->id])
                ->whereIn('state', [OrdersState::PAY['value'], OrdersState::WAIT_START['value'], OrdersState::SERVICE_ING['value']])->select();
            if ($ordersSub->isEmpty()) {
                throw new \Exception('当前订单无法进行退款，请联系客服。');
            }
            $MassageOrdersRefund = new MassageOrdersRefund();
            $MassageOrdersRefund->saas_appid = $saas_appid;
            $MassageOrdersRefund->orders_id = $order->id;
            $MassageOrdersRefund->orders_state = $order->state;
            $MassageOrdersRefund->use_role = $use_role;
            $MassageOrdersRefund->refund_message = $request->post('refund_message');
            $overtimeOrder = MassageOrders::where(['orders_id' => $order->id])->select();
            if ($overtimeOrder) {
                foreach ($overtimeOrder as $item) {
                    $item->state = OrdersState::REFUNDING['value'];
                    $item->save();
                }
            }
            $MassageUser = MassageUser::alias('u')->where(['u.id' => $order->uid])
                ->join('MassageUserWechat uw', 'uw.uid=u.id', 'left')
                ->field('u.nickname,u.mobile,uw.openid')
                ->find();
            if ($refund_examine_state && in_array($order->state, [OrdersState::PAY['value'], OrdersState::WAIT_START['value']])) {
                $order->state = OrdersState::REFUNDING['value'];
                $order->save();
                /* 退款业务 */
                MassageOrders::refund($order->id, $MassageOrdersRefund);
                /* 退款业务 */
                $MassageOrdersRefund->examine = Examine::YES['value'];
                $MassageOrdersRefund->save();
                $notice = new Notice();
                if ($MassageUser) {
                    $notice->addUSER($MassageUser->mobile, $MassageUser->openid);
                }
                $MassageUserT = MassageUser::alias('u')->where(['u.id' => $order->alias_id])
                    ->join('MassageUserWechat uw', 'uw.uid=u.id', 'left')
                    ->field('u.nickname,u.mobile,uw.openid')
                    ->find();
                if ($MassageUserT) {
                    $notice->addTECHNICIAN($MassageUserT->mobile, $MassageUserT->openid);
                }
                $MassageOrdersAddress = MassageOrdersAddress::where(['orders_id' => $order->id])->find();
                $name = '(' . $order->uid . ')';
                if ($MassageOrdersAddress) {
                    $name = $MassageOrdersAddress['name'] . '(' . $order->uid . ')';
                }
                $notice->saas_appid = $order->saas_appid;
                $notice->type = NoticeType::REFUND['value'];
                $notice->setData([
                    'trade' => $order->trade,
                    'price' => $order->price,
                    'refund_price' => $MassageOrdersRefund->price,
                    'time' => date('Y-m-d H:i:s'),
                    'name' => $name,
                ]);
                $notice->send();
                Db::commit();
                return $this->json('退款成功', 9000);
            } else {
                $order->state = OrdersState::REFUNDING['value'];
                $order->save();
                $MassageOrdersRefund->examine = Examine::WAIT['value'];
                $MassageOrdersRefund->save();
                $notice = new Notice();
                $notice->saas_appid = $order->saas_appid;
                $notice->role = ['ADMIN'];
                $notice->type = NoticeType::WORK_ORDER['value'];
                $notice->setData([
                    'service_name' => '退款审核',
                    'name' => $MassageUser->nickname . '(' . $order->uid . ')',
                    'time' => date('Y-m-d H:i:s'),
                ]);
                $notice->send();
                Db::commit();
                return $this->success('退款申请已提交，等待管理员审核');
            }
        } catch (\Throwable $th) {
            Db::rollback();
            return $this->fail($th->getMessage());
        }
    }
    public function transferring(Request $request) {
        $uid = $request->uid;
        $saas_appid = $request->saas_appid;
        $trade = $request->post('trade');
        $use_role = $request->post('use_role', 'technician');
        Db::startTrans();
        try {
            $where = [];
            if ($use_role == ActionIdentity::TECHNICIAN['value']) {
                $where['alias_id'] = $uid;
            } else {
                $where['uid'] = $uid;
            }
            $where['trade'] = $trade;
            $where['saas_appid'] = $saas_appid;
            $order = MassageOrders::where($where)->find();
            if (!$order) {
                throw new \Exception('订单不存在');
            }
            $MassageAppointmentService = MassageAppointmentService::where(['orders_id' => $order->id])->select();
            $state = null;
            foreach ($MassageAppointmentService as $item) {
                if (!in_array($item->state, [ServiceState::WAIT_START['value'], ServiceState::TRAVELING['value'], ServiceState::ARRIVAL['value']])) {
                    throw new \Exception('订单一开始服务不可转单');
                }
                $state = $item->state;
                $item->state = OrdersState::TRANSFERRING_ORDERS['value'];
                $item->save();
            }
            $MassageOrdersTransferring = new MassageOrdersTransferring();
            $MassageOrdersTransferring->saas_appid = $saas_appid;
            $MassageOrdersTransferring->orders_id = $order->id;
            $MassageOrdersTransferring->technician_id = $order->alias_id;
            $MassageOrdersTransferring->orders_state = $order->state;
            $MassageOrdersTransferring->service_state = $state;
            $MassageOrdersTransferring->use_role = $use_role;
            $MassageOrdersTransferring->transferring_message = $request->post('transferring_message');
            $MassageOrdersTransferring->examine = Examine::WAIT['value'];
            $MassageOrdersTransferring->save();
            $order->state = OrdersState::TRANSFERRING_ORDERS['value'];
            $order->save();
            Db::commit();
        } catch (\Throwable $th) {
            Db::rollback();
            return $this->fail($th->getMessage());
        }
        $MassageUser = MassageUser::alias('u')->where(['u.id' => $order->uid])
            ->join('MassageUserWechat uw', 'uw.uid=u.id', 'left')
            ->field('u.nickname,u.mobile,uw.openid')
            ->find();
        $notice = new Notice();
        $notice->saas_appid = $order->saas_appid;
        $notice->role = ['ADMIN'];
        $notice->type = NoticeType::WORK_ORDER['value'];
        $notice->setData([
            'service_name' => '转单审核',
            'name' => $MassageUser->nickname . '(' . $order->uid . ')',
            'time' => date('Y-m-d H:i:s'),
        ]);
        $notice->send();
        return $this->success('退转单申请已提交，等待管理员审核');
    }
}
